package com.qulai.amazon_us.core.basic.Supplier;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qulai.amazon_us.domain.basic.Image;
import com.qulai.amazon_us.domain.basic.Product;
import com.qulai.amazon_us.mapper.basic.ImageMapper;
import com.qulai.amazon_us.mapper.basic.ProductMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Component
public class DobaSupplier {
    private static final Logger logger = LoggerFactory.getLogger(DobaSupplier.class);

    private static final String APP_KEY = "202502051336757526846242816";
    private static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhhEFoishJHyVlDRCmwDyX2Ii2XAUJMJ6Pmfxa4gAIUYvqTwJyjhNHIAWHLQud8vr4ZmizPCKBt4udwr6nRdN5i5+ZiE8vZ8nN/IBz+miXsxAZhI+5C2CCeCpeoTN5bk/zqAlZ1epprwr2CWuioFwTC1fLx2mNwsgtbPPFCtYUfzomYzsjrxN54bBW/KYiF+wQlNJ2uIYYEc2SMV2n2zL8O2epPzYvQxRBicl8EpEe1Y++JFbu34MYQfFeMADIj9zZgw62GQYRJd8OqqXyufNhg03wTAZG91/RlqeBtEiVpual+uP/oT6w2cvC8gkGuGksSBHv6XvjpeHCY9Do20kDQIDAQAB";
    private static final String PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCGEQWiKyEkfJWUNEKbAPJfYiLZcBQkwno+Z/FriAAhRi+pPAnKOE0cgBYctC53y+vhmaLM8IoG3i53CvqdF03mLn5mITy9nyc38gHP6aJezEBmEj7kLYIJ4Kl6hM3luT/OoCVnV6mmvCvYJa6KgXBMLV8vHaY3CyC1s88UK1hR/OiZjOyOvE3nhsFb8piIX7BCU0na4hhgRzZIxXafbMvw7Z6k/Ni9DFEGJyXwSkR7Vj74kVu7fgxhB8V4wAMiP3NmDDrYZBhEl3w6qpfK582GDTfBMBkb3X9GWp4G0SJWm5qX64/+hPrDZy8LyCQa4aSxIEe/pe+Ol4cJj0OjbSQNAgMBAAECggEBAIEzKlCsa9Yz0hrvejjS4sEVXCxcHK2IVjKKDVjpyeZHM2tOlsixFW8f6S9kXVvJw9q4KvKB5SLVP8YtaHO3n7TynZFi+pxrImqB6UkrCPV+tZkogD95s9Y9ElcmYR7ANkO0hhdfnfk3YrF9LwX/0+810oMfea2WJcG2NRxk4UqwkaGrwrWQ17oxigugf/f1yhCVobmJ9qd+jan4FqPBIFg95mxOGalewsTuZbRh+YtZYTvjoLDUDFQahe9ilALoKd6lZjI8TuqErTQVPGUf0Gbl2B5jHIz7Ilp33OvHOKx5BsO1EL4ADvssqSn0IqAYIDHbncquyRJJ3Vg8bfjHYakCgYEA+XRJk5IwN/Lx9vv866KFLpjNGLmnQAm83biy92mrUKXMHMKOQGdDaYkvJsgsHYYtU0u35hMAGOpNA3MF70jtO7yspsO/ZwSfdX2w7+Ro2YP8P9Ja0R4EsAq277EldsIxci2+1bh+F65otjCaF8UXpNeqshl9D+z4a7vJ7ijuQ8cCgYEAiZWdmwSXQGGkmwshIwSeiIsRl7kNcnCKql99djRByxb++npt/LjQXrKfN9n6oyFH1kbOuVrgOz1OgGIXjLigVo2DhRncqgYEGzqNuNFHqu6LYggpU8MXVry+vEFWqXs6gH+odSj2GBxZJMV/Vt/2w1+24IEy96OOIf/d54HA8YsCgYEAxvmV0qsR4R7dGCfplz7cQs3JEsbLfI4H40d3IVhdOQf2pp4df4uevuiY/rM+VRJ4xu8nsdJICpehdHXkLviZmkOl56NN4etTEhF+9+rWI2Je671riVALZyw0vT4s5uyBKlUI2kq98T/B8EkWMI2ajXclhchE9FYN1UlGCb0GSHMCgYB/aCZv1BuAiitVTEQeWnu4dBgRiVMzg5ZVWWIkYRYATMZIC7HokviaiQy6OshH4lzUx/NNYCM/mHEmoC+wp5QLMrb1PdLDPBj3Ygy1dk/IsWgvmuEyaPom31g9mr/26F9veUf1Xr4t66p9S8q1F2c621rNobch7bqEL549cUHMKwKBgQCBgFMvO/drGYJB/W/rnX23KfSd6FJ06b9q+M3qG26oQhoAToqJOvr8ReRBSHwfigF6KTifT74fq52qR2csgbXadWI7OgRpgRPkvbepe7OaM6N24a3Ob4YZ4zkFvd8M54KEB5HuLgK5A1wu68aGurHFepEZGWwnnpNLhiCozpPBjw==";

    private static final Map<String, String> REGION_CODE_MAP = Map.of("US", "US");
    private static final int BATCH_SIZE = 50;
    private static final int MAX_THREADS = 26;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ImageMapper imageMapper;

    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(20))
            .build();

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 生成请求头
     */
    private String[] generateRequestHeaders() {
        long timestamp = System.currentTimeMillis();
        String sign = sign(timestamp);

        return new String[]{
                "appKey", APP_KEY,
                "signType", "rsa2",
                "timestamp", String.valueOf(timestamp),
                "sign", sign
        };
    }

    /**
     * 签名
     */
    private String sign(long timestamp) {
        try {
            String contentForSign = "appKey=" + APP_KEY + "&signType=rsa2&timestamp=" + timestamp;

            byte[] privateKeyBytes = Base64.getDecoder().decode(PRIVATE_KEY);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);
            signature.update(contentForSign.getBytes(StandardCharsets.UTF_8));
            byte[] signBytes = signature.sign();
            return Base64.getEncoder().encodeToString(signBytes);

        } catch (Exception e) {
            logger.error("Error generating signature: {}", e.getMessage(), e);
            return "";
        }
    }

    /**
     * 随机休眠
     */
    private void sleepRandomDuration() {
        try {
            int sleepTime = new Random().nextInt(1000) + 500; // 500-1500毫秒
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }


    /**
     * 更新Doba供应商的价格和库存
     */
    public void updatePriceAndQuantity() {
        LocalDateTime now = LocalDateTime.now();
        String startTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        logger.info("{}, start: doba update price and quantity...", startTime);
        try {
            // 获取所有sku列表
            List<Product> skuListPage = productMapper.selectProductsByPlatform("DB");
            ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
            List<Future<?>> futures = new ArrayList<>();
            // 分批处理
            for (int i = 0; i < skuListPage.size(); i += BATCH_SIZE) {
                int endIndex = Math.min(i + BATCH_SIZE, skuListPage.size());
                List<Product> skuList = skuListPage.subList(i, endIndex);
                futures.add(executor.submit(() -> {
                    try {
                        threadDobaUpdatePriceQuantity(skuList);
                    } catch (Exception e) {
                        logger.error("Task execution failed: {}", e.getMessage(), e);
                    }
                }));
                Thread.sleep(100);
                if (futures.size() >= MAX_THREADS) {
                    // 随机休眠
                    sleepRandomDuration();
                }
            }
            executor.shutdown();
            LocalDateTime endTime = LocalDateTime.now();
            logger.info("{}, Doba price and quantity fetch completed.", endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        } catch (Exception e) {
            logger.error("Error updating Doba price and quantity: {}", e.getMessage(), e);
        }
    }

    /**
     * 线程处理Doba价格和库存更新
     */
    private void threadDobaUpdatePriceQuantity(List<Product> skuList) {

        try {
            // 构建SKU映射
            Map<String, String> skuIdMap = new HashMap<>();
            Map<String, Integer> skuQuantityMap = new HashMap<>();
            Map<String, Integer> skuPublishedMap = new HashMap<>();
            Map<String, BigDecimal> skuPriceMap = new HashMap<>();
            List<String> forSkus = new ArrayList<>();
            for (Product product : skuList) {
                skuIdMap.put(product.getSku(), product.getId());
                skuQuantityMap.put(product.getSku(), product.getQuantity());
                skuPublishedMap.put(product.getSku(), product.getPublished());
                if (product.getPrice() != null) {
                    skuPriceMap.put(product.getSku(), new BigDecimal(product.getPrice()));
                }
                forSkus.add(product.getSku());
            }

            String skuStr = String.join(",", forSkus);
            Map<String, Map<String, Object>> quantityPriceDict = getProductPriceAndInventory(skuStr);
            if (quantityPriceDict == null) {
                return;
            }
            List<Product> needUpdateList = new ArrayList<>();
            List<Image> needUpdateImageList = new ArrayList<>();
            for (String sku : forSkus) {
                Map<String, Object> quantityPrice = quantityPriceDict.getOrDefault(sku, new HashMap<>());
                BigDecimal price = BigDecimal.ZERO;
                int published = 0;
                if (quantityPrice.containsKey("price") && quantityPrice.get("price") != null && Float.parseFloat(quantityPrice.get("price").toString()) > 0) {
                    published = 1;
                    price = new BigDecimal(quantityPrice.get("price").toString()).setScale(2, RoundingMode.HALF_UP);
                }
                int quantity = 0;
                if (quantityPrice.containsKey("quantity") && quantityPrice.get("quantity") != null) {
                    quantity = Integer.parseInt(quantityPrice.get("quantity").toString());
                }
                int oldQuantity = skuQuantityMap.getOrDefault(sku, 0);
                BigDecimal oldPrice = skuPriceMap.getOrDefault(sku, BigDecimal.ZERO);
                int oldPublished = skuPublishedMap.getOrDefault(sku, 1);

                if (quantity != oldQuantity || !price.equals(oldPrice) || published != oldPublished) {
                    Product product = new Product();
                    product.setId(skuIdMap.get(sku));
                    product.setPublished(published);
                    product.setQuantity(quantity);
                    product.setPrice(price.toString());
                    needUpdateList.add(product);
                }
                if (published != oldPublished) {
                    Image image = new Image();
                    image.setBasicId(Long.valueOf(skuIdMap.get(sku)));
                    image.setPublished(published);
                    needUpdateImageList.add(image);
                }
            }

            if (!needUpdateList.isEmpty()) {
                productMapper.batchUpdateProducts(needUpdateList);
            }
            if (!needUpdateImageList.isEmpty()) {
                imageMapper.batchUpdatePublished(needUpdateImageList);
            }
        } catch (Exception e) {
            logger.error("Error in threadDobaUpdatePriceQuantity: {}", e.getMessage(), e);
        }
    }

    /**
     * 查询库存和价格
     *
     * @param itemNos 商品编号，用逗号分隔
     * @return 价格和库存信息
     */
    private Map<String, Map<String, Object>> getProductPriceAndInventory(String itemNos) {
        String url = "https://openapi.doba.com/api/goods/doba/stock";
        try {
            String encodedItemNos = URLEncoder.encode(itemNos, StandardCharsets.UTF_8);
            String requestUrl = url + "?itemNo=" + encodedItemNos;
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(requestUrl))
                    .headers(generateRequestHeaders())
                    .GET()
                    .timeout(Duration.ofSeconds(20))
                    .build();
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() == 200) {
                JsonNode data = objectMapper.readTree(response.body());
                if ("000000".equals(data.get("responseCode").asText())) {
                    JsonNode businessData = data.get("businessData");
                    if ("000000".equals(businessData.get("businessStatus").asText()) &&
                            "Success".equals(businessData.get("businessMessage").asText())) {
                        JsonNode products = businessData.get("data");
                        Map<String, Map<String, Object>> quantityPriceMap = new HashMap<>();
                        for (JsonNode product : products) {
                            String itemNo = product.get("itemNo").asText();
                            Map<String, Object> priceQuantity = new HashMap<>();
                            priceQuantity.put("price", product.get("sellingPrice").asText());
                            priceQuantity.put("quantity", product.get("availableNum").asInt());

                            quantityPriceMap.put(itemNo, priceQuantity);
                        }
                        return quantityPriceMap;
                    } else {
                        logger.error("Business error: {}", businessData);
                    }
                } else {
                    logger.error("API error: {}", data);
                }
            }
            logger.error("Response error: {}", response.body());
            return null;
        } catch (Exception e) {
            logger.error("Error getting product price and inventory: {}", e.getMessage(), e);
            return null;
        }
    }
}
